Section 1: Motivation
Vishnu’s section
Section 2: Methodology
Initial exploration: Cross Correlation
Our first approach to this DAP looked at the relationship between the indicator and the signal more generally. We first used cross correlation analysis on the time series to identify the relationship between indicators and cases across a time period. We calculated the cross correlation of the two time series for each county, and looked at the max cross correlation values and the lag in days for where that maximum cross correlation occured. An example of this data over all observed counties for the Drs Visits indicator signal: 
However, this is a more general analysis than our DAP directive, which is dealing with periods of increase specifically, rather then the general relationship between two signals. For this DAP, we don’t care if there is a cross correlation or not between indicators and cases when the signals are flat, decreasing, or even rising slightly. We care about sharp upswings in cases, something significant within a county. We want to analyze the leadingness of a signficant indicator rise in relation to a significant case rise. To do this, we need to define and find periods of significant rise in these signals.
Identifying Rises in Signals
We determined that to ascertain leadingness of an indicator, we care about whether the indicator began to rise significantly before cases began to rise significantly. So we need a decision rule for identifying significant rises.
Starting at the Peak
At first we experimented with finding the peak of a signal in a given time period and identifying the closest local minimum that precedes the peak. However this is not always the point at which the signal actually begins to rise (could be caught in a shallow local minimum), and does not gaurantee the rise would be a lengthy or a steep one. This method also only picks one rise period for a signal for every county for the given time period, which isn’t always reflective of the signal’s actual behavior.
Best Fit Line
One option we tried was calculating a line of best fit for the signal for fixed time periods within a larger time period. For example, calculating a line of best fit for every 21 day window within a 3 month window and choosing the period that has the highest slope as the most significant rise period in that county for that signal.
- Where this worked well:
- This method finds periods of consistent rise, not allowing the signal to vary a lot between the beginning and ending points of the rise period.
- Where this had drawbacks:
- Many times this method only selects the larger end of a rise, since the window is a fixed size, and leaves out where the rise starts.
- This method also only allows for one rise per time period/county.
Example plot
Estimated Derivative
We then tried using multiple different derivative estimate methods to identify periods where the estimated derivative at each point is over a certain threshold.
- Where this worked well:
- It can find smaller periods of continuous rise that are flexible in length.
- It allows for multiple periods of rise per time period.
- Where this had drawbacks:
- Using a large fixed window size (14 or 21 days) in the derivative estimation function means that many identified points are actually within a decreasing period after a rise.
- It can label rises too liberally, identifying very small bumps in the signal as rises.
Example plot
Blue is using smoothing spline method, Red is using local linear regression (Purple is where both methods marked the same point)
Final Method
We saw that smoothing the signal first (on top of the 7 day average smoothing from the API) and using the derivative method produced the best results. Twekaing this method with some other decision rules gave us our best outcome for finding periods of significant rise.
Final criteria for rise periods: A period is a significant rise if
First derivative at each point is > 0 - aka signal is in fact rising on every day
Period is > a certain number of days (for this analysis we used 5) - aka it’s not just a spurius rise
- Each first derivative is > a certain % of other derivatives in time period (for this analysis we used 75%) - aka making sure the rise is a significant one for this county. This ties this decision to the specific time period we are looking at, and the rise point identifications can change based on the time period because of this criteria.
Magnitude of increase from start to end of period is > a certain threshold (for this analysis we used 20%) - aka another way to make sure that the rise is significant, not just a slight uptick in cases
Finally, we take the point at the beginning of each rise period as the best estimation of a point of inflection where a signal begins to rise significantly, so we can answer the question: Does the beginning of a rise in the indicator come before the beginning of a rise in cases?
In our analysis, we look at this on a county by county basis, for specific time periods during the pandemic, like the “Summer wave” or the “Fall wave.”
County Selection
In our analysis, we include all counties that have greater than 2000 cases (a little over 20 cases a day for a 3 month window), 80 days of indicator data for a 3 month window, and do not have zero or negative values for either cases or the indicator.
Recall and Precision
TODO
Walkthrough
Step 1. Get and prepare county data
As an example, we’ll use our Dr Visits % CLI as our indicator, and the summer as our time period. We use our LeadingIndicatorTools package for all our main functions.
Step 2. We can plot the Drs Visits and the case signal together for an example county.
plot_signals(drs_summer, "01003", smooth_and_show_increase_point=FALSE, "Drs Visits")

Step 3. Now we can mark the rise points (the points at the beginning of the rise periods) for the Drs Visits and Cases signal.
In the respective rise point columns, the day is marked with a 1 if it is found to be a rise point for that signal. We can see here that there is a rise point for Drs Vists on 6/18 and for cases on 6/26.
drs_summer[1]
[[1]]
NA
Step 4. Now we can plot the smoothed signal with the beginning rise points.
We can see that Drs Visits begins to rise before cases rise. TODO I think we need to tweak our rise point method a bit so we don’t have these “double counting” points on a rise.
plot_signals(drs_summer, "01003", smooth_and_show_increase_point=TRUE, "Drs Visits")

Section 3: Analysis
Doctor Visits
We can plot some of the counties where rises in the doctor visits indicator consistently lead rises in cases.
Examples from the Summer
Some inputs were not uniquely matched; returning only the first match in each case.







































Examples from the Fall
Some inputs were not uniquely matched; returning only the first match in each case.






















Examples of counties that show successes in both Summer and Fall
Some inputs were not uniquely matched; returning only the first match in each case.Some inputs were not uniquely matched; returning only the first match in each case.









Fall Frequencies
We can also look at the distribution of the frequency of the number of days by which Doctor Visits’ rises lead case rises in successful counties

Summer Frequencies
We can also look at the distribution of the frequency of the number of days by which Doctor Visits’ rises lead case rises in successful counties

Change Healthcare
We can plot some of the counties where rises in the Change Healthcare indicator consistently lead rises in cases.
Examples from the Summer
Some inputs were not uniquely matched; returning only the first match in each case.Some inputs were not uniquely matched; returning only the first match in each case.Some inputs were not uniquely matched; returning only the first match in each case.









































Examples of counties that show successes in both Summer and Fall




Fall Frequencies
We can also look at the distribution of the frequency of the number of days by which Change Healthcare rises lead case rises in successful counties

Summer Frequencies
We can also look at the distribution of the frequency of the number of days by which Change Healthcare rises lead case rises in successful counties

Indicator Combination
We can plot some of the counties where rises in the indicator combination consistently lead rises in cases.
Examples from the Summer
Some inputs were not uniquely matched; returning only the first match in each case.Some inputs were not uniquely matched; returning only the first match in each case.



































Examples of counties that show successes in both Summer and Fall





Fall Frequencies
We can also look at the distribution of the frequency of the number of days by which Indicator Combination rises lead case rises in successful counties

Summer Frequencies
We can also look at the distribution of the frequency of the number of days by which Indicator Combination rises lead case rises in successful counties

Note that the counties shown and counted as “successful” here met the following criteria: All indicator rise points were followed by a case rise point within 3 to 14 days (and all case rise points were preceded by an indicator rise point within the same time period). This means that the displayed counties almost always have only one rise point per signal and case (the more rise points the harder it is to meet the criteria).
Section 5: Conclusions and Limitations
LS0tCnRpdGxlOiAiTGVhZGluZyBJbmRpY2F0b3JzIERBUCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IsIHJlc3VsdHM9J2hpZGUnLCBlY2hvPUZBTFNFfQpzb3VyY2UoIkxlYWRpbmdJbmRpY2F0b3JUb29scy5SIikKbGlicmFyeShjb3ZpZGNhc3QpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGFzc2VydHRoYXQpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShkcGx5cikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ2dwdWJyKQpgYGAKCiMjIDxzcGFuPlNlY3Rpb24gMTogTW90aXZhdGlvbjwvc3Bhbj4KVmlzaG51J3Mgc2VjdGlvbgoKIyMgPHNwYW4+U2VjdGlvbiAyOiBNZXRob2RvbG9neTwvc3Bhbj4KCjxkZXRhaWxzPgo8c3VtbWFyeT4qKkluaXRpYWwgZXhwbG9yYXRpb246IENyb3NzIENvcnJlbGF0aW9uKio8L3N1bW1hcnk+CgpPdXIgZmlyc3QgYXBwcm9hY2ggdG8gdGhpcyBEQVAgbG9va2VkIGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgaW5kaWNhdG9yIGFuZCB0aGUgc2lnbmFsIG1vcmUgZ2VuZXJhbGx5LiBXZSBmaXJzdCB1c2VkIGNyb3NzIGNvcnJlbGF0aW9uIGFuYWx5c2lzIG9uIHRoZSB0aW1lIHNlcmllcyB0byBpZGVudGlmeSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gaW5kaWNhdG9ycyBhbmQgY2FzZXMgYWNyb3NzIGEgdGltZSBwZXJpb2QuIFdlIGNhbGN1bGF0ZWQgdGhlIGNyb3NzIGNvcnJlbGF0aW9uIG9mIHRoZSB0d28gdGltZSBzZXJpZXMgZm9yIGVhY2ggY291bnR5LCBhbmQgbG9va2VkIGF0IHRoZSBtYXggY3Jvc3MgY29ycmVsYXRpb24gdmFsdWVzIGFuZCB0aGUgbGFnIGluIGRheXMgZm9yIHdoZXJlIHRoYXQgbWF4aW11bSBjcm9zcyBjb3JyZWxhdGlvbiBvY2N1cmVkLiBBbiBleGFtcGxlIG9mIHRoaXMgZGF0YSBvdmVyIGFsbCBvYnNlcnZlZCBjb3VudGllcyBmb3IgdGhlIERycyBWaXNpdHMgaW5kaWNhdG9yIHNpZ25hbDogIVtjcm9zc19jb3JyZWxhdGlvbl9wbG90XShjcm9zc19jb3JyZWxhdGlvbl9wbG90LnBuZykKCkhvd2V2ZXIsIHRoaXMgaXMgYSBtb3JlIGdlbmVyYWwgYW5hbHlzaXMgdGhhbiBvdXIgREFQIGRpcmVjdGl2ZSwgd2hpY2ggaXMgZGVhbGluZyB3aXRoICoqcGVyaW9kcyBvZiBpbmNyZWFzZSoqIHNwZWNpZmljYWxseSwgcmF0aGVyIHRoZW4gdGhlIGdlbmVyYWwgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHNpZ25hbHMuIEZvciB0aGlzIERBUCwgd2UgZG9uJ3QgY2FyZSBpZiB0aGVyZSBpcyBhIGNyb3NzIGNvcnJlbGF0aW9uIG9yIG5vdCAgYmV0d2VlbiBpbmRpY2F0b3JzIGFuZCBjYXNlcyB3aGVuIHRoZSBzaWduYWxzIGFyZSBmbGF0LCBkZWNyZWFzaW5nLCBvciBldmVuIHJpc2luZyBzbGlnaHRseS4gV2UgY2FyZSBhYm91dCBzaGFycCB1cHN3aW5ncyBpbiBjYXNlcywgc29tZXRoaW5nIHNpZ25pZmljYW50IHdpdGhpbiBhIGNvdW50eS4gV2Ugd2FudCB0byBhbmFseXplIHRoZSBsZWFkaW5nbmVzcyBvZiBhICoqc2lnbmZpY2FudCBpbmRpY2F0b3IgcmlzZSoqIGluIHJlbGF0aW9uIHRvIGEgKipzaWduaWZpY2FudCBjYXNlIHJpc2UqKi4gVG8gZG8gdGhpcywgd2UgbmVlZCB0byBkZWZpbmUgYW5kIGZpbmQgcGVyaW9kcyBvZiBzaWduaWZpY2FudCByaXNlIGluIHRoZXNlIHNpZ25hbHMuCjwvZGV0YWlscz4KCiMjIyMgSWRlbnRpZnlpbmcgUmlzZXMgaW4gU2lnbmFscwoKV2UgZGV0ZXJtaW5lZCB0aGF0IHRvIGFzY2VydGFpbiBsZWFkaW5nbmVzcyBvZiBhbiBpbmRpY2F0b3IsIHdlIGNhcmUgYWJvdXQgd2hldGhlciB0aGUgaW5kaWNhdG9yIGJlZ2FuIHRvIHJpc2Ugc2lnbmlmaWNhbnRseSBiZWZvcmUgY2FzZXMgYmVnYW4gdG8gcmlzZSBzaWduaWZpY2FudGx5LiBTbyB3ZSBuZWVkIGEgZGVjaXNpb24gcnVsZSBmb3IgaWRlbnRpZnlpbmcgc2lnbmlmaWNhbnQgcmlzZXMuCgoqKlN0YXJ0aW5nIGF0IHRoZSBQZWFrKio8YnI+CkF0IGZpcnN0IHdlIGV4cGVyaW1lbnRlZCB3aXRoIGZpbmRpbmcgdGhlIHBlYWsgb2YgYSBzaWduYWwgaW4gYSBnaXZlbiB0aW1lIHBlcmlvZCBhbmQgaWRlbnRpZnlpbmcgdGhlIGNsb3Nlc3QgbG9jYWwgbWluaW11bSB0aGF0IHByZWNlZGVzIHRoZSBwZWFrLiBIb3dldmVyIHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgcG9pbnQgYXQgd2hpY2ggdGhlIHNpZ25hbCBhY3R1YWxseSBiZWdpbnMgdG8gcmlzZSAoY291bGQgYmUgY2F1Z2h0IGluIGEgc2hhbGxvdyBsb2NhbCBtaW5pbXVtKSwgYW5kIGRvZXMgbm90IGdhdXJhbnRlZSB0aGUgcmlzZSB3b3VsZCBiZSBhIGxlbmd0aHkgb3IgYSBzdGVlcCBvbmUuIFRoaXMgbWV0aG9kIGFsc28gb25seSBwaWNrcyBvbmUgcmlzZSBwZXJpb2QgZm9yIGEgc2lnbmFsIGZvciBldmVyeSBjb3VudHkgZm9yIHRoZSBnaXZlbiB0aW1lIHBlcmlvZCwgd2hpY2ggaXNuJ3QgYWx3YXlzIHJlZmxlY3RpdmUgb2YgdGhlIHNpZ25hbCdzIGFjdHVhbCBiZWhhdmlvci4KCioqQmVzdCBGaXQgTGluZSoqPGJyPgpPbmUgb3B0aW9uIHdlIHRyaWVkIHdhcyBjYWxjdWxhdGluZyBhIGxpbmUgb2YgYmVzdCBmaXQgZm9yIHRoZSBzaWduYWwgZm9yIGZpeGVkIHRpbWUgcGVyaW9kcyB3aXRoaW4gYSBsYXJnZXIgdGltZSBwZXJpb2QuIEZvciBleGFtcGxlLCBjYWxjdWxhdGluZyBhIGxpbmUgb2YgYmVzdCBmaXQgZm9yIGV2ZXJ5IDIxIGRheSB3aW5kb3cgd2l0aGluIGEgMyBtb250aCB3aW5kb3cgYW5kIGNob29zaW5nIHRoZSBwZXJpb2QgdGhhdCBoYXMgdGhlIGhpZ2hlc3Qgc2xvcGUgYXMgdGhlIG1vc3Qgc2lnbmlmaWNhbnQgcmlzZSBwZXJpb2QgaW4gdGhhdCBjb3VudHkgZm9yIHRoYXQgc2lnbmFsLgoKICAtIFdoZXJlIHRoaXMgd29ya2VkIHdlbGw6CiAgICAtIFRoaXMgbWV0aG9kIGZpbmRzIHBlcmlvZHMgb2YgY29uc2lzdGVudCByaXNlLCBub3QgYWxsb3dpbmcgdGhlIHNpZ25hbCB0byB2YXJ5IGEgbG90IGJldHdlZW4gdGhlIGJlZ2lubmluZyBhbmQgZW5kaW5nIHBvaW50cyBvZiB0aGUgcmlzZSBwZXJpb2QuCiAgLSBXaGVyZSB0aGlzIGhhZCBkcmF3YmFja3M6IAogICAgLSBNYW55IHRpbWVzIHRoaXMgbWV0aG9kIG9ubHkgc2VsZWN0cyB0aGUgbGFyZ2VyIGVuZCBvZiBhIHJpc2UsIHNpbmNlIHRoZSB3aW5kb3cgaXMgYSBmaXhlZCBzaXplLCBhbmQgbGVhdmVzIG91dCB3aGVyZSB0aGUgcmlzZSBzdGFydHMuCiAgICAtIFRoaXMgbWV0aG9kIGFsc28gb25seSBhbGxvd3MgZm9yIG9uZSByaXNlIHBlciB0aW1lIHBlcmlvZC9jb3VudHkuCiAgICAKPGRldGFpbHM+CjxzdW1tYXJ5PipFeGFtcGxlIHBsb3QqPC9zdW1tYXJ5PgoKIVtiZXN0X2ZpdF9wbG90XShiZXN0X2ZpdC5wbmcpCjwvZGV0YWlscz4KPGJyPgoKKipFc3RpbWF0ZWQgRGVyaXZhdGl2ZSoqPGJyPgpXZSB0aGVuIHRyaWVkIHVzaW5nIG11bHRpcGxlIGRpZmZlcmVudCBkZXJpdmF0aXZlIGVzdGltYXRlIG1ldGhvZHMgdG8gaWRlbnRpZnkgcGVyaW9kcyB3aGVyZSB0aGUgZXN0aW1hdGVkIGRlcml2YXRpdmUgYXQgZWFjaCBwb2ludCBpcyBvdmVyIGEgY2VydGFpbiB0aHJlc2hvbGQuCgogIC0gV2hlcmUgdGhpcyB3b3JrZWQgd2VsbDoKICAgIC0gSXQgY2FuIGZpbmQgc21hbGxlciBwZXJpb2RzIG9mIGNvbnRpbnVvdXMgcmlzZSB0aGF0IGFyZSBmbGV4aWJsZSBpbiBsZW5ndGguCiAgICAtIEl0IGFsbG93cyBmb3IgbXVsdGlwbGUgcGVyaW9kcyBvZiByaXNlIHBlciB0aW1lIHBlcmlvZC4KICAtIFdoZXJlIHRoaXMgaGFkIGRyYXdiYWNrczogCiAgICAgLSBVc2luZyBhIGxhcmdlIGZpeGVkIHdpbmRvdyBzaXplICgxNCBvciAyMSBkYXlzKSBpbiB0aGUgZGVyaXZhdGl2ZSBlc3RpbWF0aW9uIGZ1bmN0aW9uIG1lYW5zIHRoYXQgbWFueSBpZGVudGlmaWVkIHBvaW50cyBhcmUgYWN0dWFsbHkgd2l0aGluIGEgZGVjcmVhc2luZyBwZXJpb2QgYWZ0ZXIgYSByaXNlLgogICAgIC0gSXQgY2FuIGxhYmVsIHJpc2VzIHRvbyBsaWJlcmFsbHksIGlkZW50aWZ5aW5nIHZlcnkgc21hbGwgYnVtcHMgaW4gdGhlIHNpZ25hbCBhcyByaXNlcy4KCjxkZXRhaWxzPgo8c3VtbWFyeT4qRXhhbXBsZSBwbG90Kjwvc3VtbWFyeT4KCkJsdWUgaXMgdXNpbmcgc21vb3RoaW5nIHNwbGluZSBtZXRob2QsIFJlZCBpcyB1c2luZyBsb2NhbCBsaW5lYXIgcmVncmVzc2lvbiAoUHVycGxlIGlzIHdoZXJlIGJvdGggbWV0aG9kcyBtYXJrZWQgdGhlIHNhbWUgcG9pbnQpCiFbZXN0aW1hdGVkX2Rlcml2X3Bsb3RdKGVzdGltYXRlZF9kZXJpdi5wbmcpCjwvZGV0YWlscz4KPGJyPgoKIyMjIyMgKipGaW5hbCBNZXRob2QqKiAKV2Ugc2F3IHRoYXQgc21vb3RoaW5nIHRoZSBzaWduYWwgZmlyc3QgKG9uIHRvcCBvZiB0aGUgNyBkYXkgYXZlcmFnZSBzbW9vdGhpbmcgZnJvbSB0aGUgQVBJKSBhbmQgdXNpbmcgdGhlIGRlcml2YXRpdmUgbWV0aG9kIHByb2R1Y2VkIHRoZSBiZXN0IHJlc3VsdHMuIFR3ZWthaW5nIHRoaXMgbWV0aG9kIHdpdGggc29tZSBvdGhlciBkZWNpc2lvbiBydWxlcyBnYXZlIHVzIG91ciBiZXN0IG91dGNvbWUgZm9yIGZpbmRpbmcgcGVyaW9kcyBvZiBzaWduaWZpY2FudCByaXNlLgoKRmluYWwgY3JpdGVyaWEgZm9yIHJpc2UgcGVyaW9kczogQSBwZXJpb2QgaXMgYSBzaWduaWZpY2FudCByaXNlIGlmCiAgCiAgMS4gRmlyc3QgZGVyaXZhdGl2ZSBhdCBlYWNoIHBvaW50IGlzID4gMCAtICpha2Egc2lnbmFsIGlzIGluIGZhY3QgcmlzaW5nIG9uIGV2ZXJ5IGRheSoKICAKICAyLiBQZXJpb2QgaXMgPiBhIGNlcnRhaW4gbnVtYmVyIG9mIGRheXMgKGZvciB0aGlzIGFuYWx5c2lzIHdlIHVzZWQgNSkgLSAqYWthIGl0J3Mgbm90IGp1c3QgYSBzcHVyaXVzIHJpc2UqCiAgCiAgMy4gRWFjaCBmaXJzdCBkZXJpdmF0aXZlIGlzID4gYSBjZXJ0YWluICUgb2Ygb3RoZXIgZGVyaXZhdGl2ZXMgaW4gdGltZSBwZXJpb2QgKGZvciB0aGlzIGFuYWx5c2lzIHdlIHVzZWQgNzUlKSAtICpha2EgbWFraW5nIHN1cmUgdGhlIHJpc2UgaXMgYSBzaWduaWZpY2FudCBvbmUgZm9yIHRoaXMgY291bnR5LiBUaGlzIHRpZXMgdGhpcyBkZWNpc2lvbiB0byB0aGUgc3BlY2lmaWMgdGltZSBwZXJpb2Qgd2UgYXJlIGxvb2tpbmcgYXQsIGFuZCB0aGUgcmlzZSBwb2ludCBpZGVudGlmaWNhdGlvbnMgY2FuIGNoYW5nZSBiYXNlZCBvbiB0aGUgdGltZSBwZXJpb2QgYmVjYXVzZSBvZiB0aGlzIGNyaXRlcmlhLioKICA0LiBNYWduaXR1ZGUgb2YgaW5jcmVhc2UgZnJvbSBzdGFydCB0byBlbmQgb2YgcGVyaW9kIGlzID4gYSBjZXJ0YWluIHRocmVzaG9sZCAoZm9yIHRoaXMgYW5hbHlzaXMgd2UgdXNlZCAyMCUpIC0gKmFrYSBhbm90aGVyIHdheSB0byBtYWtlIHN1cmUgdGhhdCB0aGUgcmlzZSBpcyBzaWduaWZpY2FudCwgbm90IGp1c3QgYSBzbGlnaHQgdXB0aWNrIGluIGNhc2VzKgogIAoKKipGaW5hbGx5KiosIHdlIHRha2UgdGhlIHBvaW50IGF0IHRoZSBiZWdpbm5pbmcgb2YgZWFjaCByaXNlIHBlcmlvZCBhcyB0aGUgYmVzdCBlc3RpbWF0aW9uIG9mIGEgcG9pbnQgb2YgaW5mbGVjdGlvbiB3aGVyZSBhIHNpZ25hbCBiZWdpbnMgdG8gcmlzZSBzaWduaWZpY2FudGx5LCBzbyB3ZSBjYW4gYW5zd2VyIHRoZSBxdWVzdGlvbjogKipEb2VzIHRoZSBiZWdpbm5pbmcgb2YgYSByaXNlIGluIHRoZSBpbmRpY2F0b3IgY29tZSBiZWZvcmUgdGhlIGJlZ2lubmluZyBvZiBhIHJpc2UgaW4gY2FzZXM/KioKCkluIG91ciBhbmFseXNpcywgd2UgbG9vayBhdCB0aGlzIG9uIGEgY291bnR5IGJ5IGNvdW50eSBiYXNpcywgZm9yIHNwZWNpZmljIHRpbWUgcGVyaW9kcyBkdXJpbmcgdGhlIHBhbmRlbWljLCBsaWtlIHRoZSAiU3VtbWVyIHdhdmUiIG9yIHRoZSAiRmFsbCB3YXZlLiIKPGJyPgo8YnI+CgojIyMjIENvdW50eSBTZWxlY3Rpb24KIEluIG91ciBhbmFseXNpcywgd2UgaW5jbHVkZSBhbGwgY291bnRpZXMgdGhhdCBoYXZlIGdyZWF0ZXIgdGhhbiAyMDAwIGNhc2VzIChhIGxpdHRsZSBvdmVyIDIwIGNhc2VzIGEgZGF5IGZvciBhIDMgbW9udGggd2luZG93KSwgODAgZGF5cyBvZiBpbmRpY2F0b3IgZGF0YSBmb3IgYSAzIG1vbnRoIHdpbmRvdywgYW5kIGRvIG5vdCBoYXZlIHplcm8gb3IgbmVnYXRpdmUgdmFsdWVzIGZvciBlaXRoZXIgY2FzZXMgb3IgdGhlIGluZGljYXRvci4KPGJyPgo8YnI+CgojIyMjIFJlY2FsbCBhbmQgUHJlY2lzaW9uClRPRE8KCjxicj4KCgojIyMgV2Fsa3Rocm91Z2gKIyMjIyMgU3RlcCAxLiBHZXQgYW5kIHByZXBhcmUgY291bnR5IGRhdGEKQXMgYW4gZXhhbXBsZSwgd2UnbGwgdXNlIG91ciBEciBWaXNpdHMgJSBDTEkgYXMgb3VyIGluZGljYXRvciwgYW5kIHRoZSBzdW1tZXIgYXMgb3VyIHRpbWUgcGVyaW9kLiBXZSB1c2Ugb3VyIExlYWRpbmdJbmRpY2F0b3JUb29scyBwYWNrYWdlIGZvciBhbGwgb3VyIG1haW4gZnVuY3Rpb25zLgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CmRyc192aXNpdHNfcHJlcGFyZWRfc3VtbWVyID0gZ2V0X2FuZF9wYXJzZV9zaWduYWxzKCIyMDIwLTA2LTAxIiwgIjIwMjAtOC0zMSIsICJkb2N0b3ItdmlzaXRzIiwgInNtb290aGVkX2Fkal9jbGkiLCAyMDAwLCA4MCkKYGBgCjxicj4KCiMjIyMgU3RlcCAyLiBXZSBjYW4gcGxvdCB0aGUgRHJzIFZpc2l0cyBhbmQgdGhlIGNhc2Ugc2lnbmFsIHRvZ2V0aGVyIGZvciBhbiBleGFtcGxlIGNvdW50eS4KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQpkcnNfc3VtbWVyID0gZ2V0X2luY3JlYXNlX3BvaW50cyhkcnNfdmlzaXRzX3ByZXBhcmVkX3N1bW1lciRjYXNlcywgZHJzX3Zpc2l0c19wcmVwYXJlZF9zdW1tZXIkaW5kaWNhdG9yKQpgYGAKCgpgYGB7cn0KcGxvdF9zaWduYWxzKGRyc19zdW1tZXIsICIwMTAwMyIsIHNtb290aF9hbmRfc2hvd19pbmNyZWFzZV9wb2ludD1GQUxTRSwgIkRycyBWaXNpdHMiKQpgYGAKPGJyPgoKIyMjIyBTdGVwIDMuIE5vdyB3ZSBjYW4gbWFyayB0aGUgcmlzZSBwb2ludHMgKHRoZSBwb2ludHMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgcmlzZSBwZXJpb2RzKSBmb3IgdGhlIERycyBWaXNpdHMgYW5kIENhc2VzIHNpZ25hbC4gCkluIHRoZSByZXNwZWN0aXZlIHJpc2UgcG9pbnQgY29sdW1ucywgdGhlIGRheSBpcyBtYXJrZWQgd2l0aCBhIDEgaWYgaXQgaXMgZm91bmQgdG8gYmUgYSByaXNlIHBvaW50IGZvciB0aGF0IHNpZ25hbC4gV2UgY2FuIHNlZSBoZXJlIHRoYXQgdGhlcmUgaXMgYSByaXNlIHBvaW50IGZvciBEcnMgVmlzdHMgb24gNi8xOCBhbmQgZm9yIGNhc2VzIG9uIDYvMjYuCmBgYHtyfQpkcnNfc3VtbWVyWzFdCmBgYAo8YnI+CgojIyMjIFN0ZXAgNC4gTm93IHdlIGNhbiBwbG90IHRoZSBzbW9vdGhlZCBzaWduYWwgd2l0aCB0aGUgYmVnaW5uaW5nIHJpc2UgcG9pbnRzLiAKV2UgY2FuIHNlZSB0aGF0IERycyBWaXNpdHMgYmVnaW5zIHRvIHJpc2UgYmVmb3JlIGNhc2VzIHJpc2UuIFRPRE8gSSB0aGluayB3ZSBuZWVkIHRvIHR3ZWFrIG91ciByaXNlIHBvaW50IG1ldGhvZCBhIGJpdCBzbyB3ZSBkb24ndCBoYXZlIHRoZXNlICJkb3VibGUgY291bnRpbmciIHBvaW50cyBvbiBhIHJpc2UuCmBgYHtyfQpwbG90X3NpZ25hbHMoZHJzX3N1bW1lciwgIjAxMDAzIiwgc21vb3RoX2FuZF9zaG93X2luY3JlYXNlX3BvaW50PVRSVUUsICJEcnMgVmlzaXRzIikKYGBgCgojIyBTZWN0aW9uIDM6IEFuYWx5c2lzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKIyMjIERvY3RvciBWaXNpdHMKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQpkcnNfdmlzaXRzX3ByZXBhcmVkX2ZhbGwgPSBnZXRfYW5kX3BhcnNlX3NpZ25hbHMoIjIwMjAtMDktMDEiLCAiMjAyMC0xMS0zMCIsICJkb2N0b3ItdmlzaXRzIiwgInNtb290aGVkX2Fkal9jbGkiLCAyMDAwLCA4MCkKZHJzX3Zpc2l0c19wcmVwYXJlZF9zdW1tZXIgPSBnZXRfYW5kX3BhcnNlX3NpZ25hbHMoIjIwMjAtMDYtMDEiLCAiMjAyMC04LTMxIiwgImRvY3Rvci12aXNpdHMiLCAic21vb3RoZWRfYWRqX2NsaSIsIDIwMDAsIDgwKQpgYGAKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQpkcnNfZmFsbCA9IGdldF9pbmNyZWFzZV9wb2ludHMoZHJzX3Zpc2l0c19wcmVwYXJlZF9mYWxsJGNhc2VzLCBkcnNfdmlzaXRzX3ByZXBhcmVkX2ZhbGwkaW5kaWNhdG9yKQpkcnNfc3VtbWVyID0gZ2V0X2luY3JlYXNlX3BvaW50cyhkcnNfdmlzaXRzX3ByZXBhcmVkX3N1bW1lciRjYXNlcywgZHJzX3Zpc2l0c19wcmVwYXJlZF9zdW1tZXIkaW5kaWNhdG9yKQoKc3VjY2Vzc19leGFtcGxlc19kcnNfZmFsbCA9IGdldF9zdWNjZXNzX2V4YW1wbGVzKGRyc19mYWxsLCBzdWNjZXNzX3dpbmRvd19tYXggPSAxNCwgc3VjY2Vzc193aW5kb3dfbWluID0gMykKc3VjY2Vzc19leGFtcGxlc19kcnNfc3VtbWVyID0gZ2V0X3N1Y2Nlc3NfZXhhbXBsZXMoZHJzX3N1bW1lciwgc3VjY2Vzc193aW5kb3dfbWF4ID0gMTQsIHN1Y2Nlc3Nfd2luZG93X21pbiA9IDMpCmBgYAoKIyMjIyBXZSBjYW4gcGxvdCBzb21lIG9mIHRoZSBjb3VudGllcyB3aGVyZSByaXNlcyBpbiB0aGUgZG9jdG9yIHZpc2l0cyBpbmRpY2F0b3IgY29uc2lzdGVudGx5IGxlYWQgcmlzZXMgaW4gY2FzZXMuIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKIyMjIyMgRXhhbXBsZXMgZnJvbSB0aGUgU3VtbWVyCmBgYHtyLCBlY2hvPUZBTFNFfQpwbG90X2V4YW1wbGVfbGlzdChzdWNjZXNzX2V4YW1wbGVzX2Ryc19zdW1tZXIsIGRyc19zdW1tZXIsICJEb2N0b3IgVmlzaXRzIENMSSIpCmBgYAoKIyMjIyMgRXhhbXBsZXMgZnJvbSB0aGUgRmFsbApgYGB7ciwgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2xpc3Qoc3VjY2Vzc19leGFtcGxlc19kcnNfZmFsbCwgZHJzX2ZhbGwsICJEb2N0b3IgVmlzaXRzIENMSSIpCmBgYAoKIyMjIyMgRXhhbXBsZXMgb2YgY291bnRpZXMgdGhhdCBzaG93IHN1Y2Nlc3NlcyBpbiBib3RoIFN1bW1lciBhbmQgRmFsbApgYGB7ciwgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2ludGVyc2VjdHMoc3VjY2Vzc19leGFtcGxlc19kcnNfc3VtbWVyLCBzdWNjZXNzX2V4YW1wbGVzX2Ryc19mYWxsLCBkcnNfc3VtbWVyLCBkcnNfZmFsbCwgIkRvY3RvciBWaXNpdHMgQ0xJIikKYGBgCiMjIyMjIEZhbGwgRnJlcXVlbmNpZXMKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmcmVxdWVuY3kgb2YgdGhlIG51bWJlciBvZiBkYXlzIGJ5IHdoaWNoIERvY3RvciBWaXNpdHMnIHJpc2VzIGxlYWQgY2FzZSByaXNlcyBpbiBzdWNjZXNzZnVsIGNvdW50aWVzCmBgYHtyIGVjaG89RkFMU0V9CnBsb3RfZGlzdHJpYnV0aW9uX2ZyZXEoc3VjY2Vzc19leGFtcGxlc19kcnNfZmFsbCwgZHJzX2ZhbGwpCmBgYAoKIyMjIyMgU3VtbWVyIEZyZXF1ZW5jaWVzCldlIGNhbiBhbHNvIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZnJlcXVlbmN5IG9mIHRoZSBudW1iZXIgb2YgZGF5cyBieSB3aGljaCBEb2N0b3IgVmlzaXRzJyByaXNlcyBsZWFkIGNhc2UgcmlzZXMgaW4gc3VjY2Vzc2Z1bCBjb3VudGllcwpgYGB7ciBlY2hvPUZBTFNFfQpwbG90X2Rpc3RyaWJ1dGlvbl9mcmVxKHN1Y2Nlc3NfZXhhbXBsZXNfZHJzX3N1bW1lciwgZHJzX3N1bW1lcikKYGBgCgoKIyMjIENoYW5nZSBIZWFsdGhjYXJlCmBgYHtyLCByZXN1bHRzPSdoaWRlJywgZWNobz1GQUxTRX0KY2hhbmdlX2hlYWx0aGNhcmVfcHJlcGFyZWRfZmFsbCA9IGdldF9hbmRfcGFyc2Vfc2lnbmFscygiMjAyMC0wOS0wMSIsICIyMDIwLTExLTMwIiwgImNobmciLCAic21vb3RoZWRfYWRqX291dHBhdGllbnRfY2xpIiwgMjAwMCwgODApCmNoYW5nZV9oZWFsdGhjYXJlX3ByZXBhcmVkX3N1bW1lciA9IGdldF9hbmRfcGFyc2Vfc2lnbmFscygiMjAyMC0wNi0wMSIsICIyMDIwLTA4LTMxIiwgImNobmciLCAic21vb3RoZWRfYWRqX291dHBhdGllbnRfY2xpIiwgMjAwMCwgODApCmBgYApgYGB7ciByZXN1bHRzPSJoaWRlIiwgZWNobz1GQUxTRX0KY2huZ19mYWxsID0gZ2V0X2luY3JlYXNlX3BvaW50cyhjaGFuZ2VfaGVhbHRoY2FyZV9wcmVwYXJlZF9mYWxsJGNhc2VzLCBjaGFuZ2VfaGVhbHRoY2FyZV9wcmVwYXJlZF9mYWxsJGluZGljYXRvcikKY2huZ19zdW1tZXIgPSBnZXRfaW5jcmVhc2VfcG9pbnRzKGNoYW5nZV9oZWFsdGhjYXJlX3ByZXBhcmVkX3N1bW1lciRjYXNlcywgY2hhbmdlX2hlYWx0aGNhcmVfcHJlcGFyZWRfc3VtbWVyJGluZGljYXRvcikKCnN1Y2Nlc3NfZXhhbXBsZXNfY2huZ19mYWxsID0gZ2V0X3N1Y2Nlc3NfZXhhbXBsZXMoY2huZ19mYWxsLCBzdWNjZXNzX3dpbmRvd19tYXggPSAxNCwgc3VjY2Vzc193aW5kb3dfbWluID0gMykKc3VjY2Vzc19leGFtcGxlc19jaG5nX3N1bW1lciA9IGdldF9zdWNjZXNzX2V4YW1wbGVzKGNobmdfc3VtbWVyLCBzdWNjZXNzX3dpbmRvd19tYXggPSAxNCwgc3VjY2Vzc193aW5kb3dfbWluID0gMykKCmNobmdfc3VjY2Vzc19pbnRlcnNlY3QgPSBpbnRlcnNlY3Qoc3VjY2Vzc19leGFtcGxlc19jaG5nX2ZhbGwsIHN1Y2Nlc3NfZXhhbXBsZXNfY2huZ19zdW1tZXIpCmBgYAojIyMjIFdlIGNhbiBwbG90IHNvbWUgb2YgdGhlIGNvdW50aWVzIHdoZXJlIHJpc2VzIGluIHRoZSBDaGFuZ2UgSGVhbHRoY2FyZSBpbmRpY2F0b3IgY29uc2lzdGVudGx5IGxlYWQgcmlzZXMgaW4gY2FzZXMuIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQojIyMjIyBFeGFtcGxlcyBmcm9tIHRoZSBTdW1tZXIKYGBge3IgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2xpc3Qoc3VjY2Vzc19leGFtcGxlc19jaG5nX3N1bW1lciwgY2huZ19zdW1tZXIsICJDaGFuZ2UgSGVhbHRoY2FyZSBDTEkiKQpgYGAKCiMjIyMjIEV4YW1wbGVzIGZyb20gdGhlIEZhbGwKYGBge3IgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2xpc3Qoc3VjY2Vzc19leGFtcGxlc19jaG5nX2ZhbGwsIGNobmdfZmFsbCwgIkNoYW5nZSBIZWFsdGhjYXJlIENMSSIpCmBgYAoKIyMjIyMgRXhhbXBsZXMgb2YgY291bnRpZXMgdGhhdCBzaG93IHN1Y2Nlc3NlcyBpbiBib3RoIFN1bW1lciBhbmQgRmFsbApgYGB7ciwgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2ludGVyc2VjdHMoc3VjY2Vzc19leGFtcGxlc19jaG5nX3N1bW1lciwgc3VjY2Vzc19leGFtcGxlc19jaG5nX2ZhbGwsIGNobmdfc3VtbWVyLCBjaG5nX2ZhbGwsICJDaGFuZ2UgSGVhbHRoY2FyZSBDTEkiKQpgYGAKCiMjIyMjIEZhbGwgRnJlcXVlbmNpZXMKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmcmVxdWVuY3kgb2YgdGhlIG51bWJlciBvZiBkYXlzIGJ5IHdoaWNoIENoYW5nZSBIZWFsdGhjYXJlIHJpc2VzIGxlYWQgY2FzZSByaXNlcyBpbiBzdWNjZXNzZnVsIGNvdW50aWVzCmBgYHtyIGVjaG89RkFMU0V9CnBsb3RfZGlzdHJpYnV0aW9uX2ZyZXEoc3VjY2Vzc19leGFtcGxlc19jaG5nX2ZhbGwsIGNobmdfZmFsbCkKYGBgCiMjIyMjIFN1bW1lciBGcmVxdWVuY2llcwpXZSBjYW4gYWxzbyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGZyZXF1ZW5jeSBvZiB0aGUgbnVtYmVyIG9mIGRheXMgYnkgd2hpY2ggQ2hhbmdlIEhlYWx0aGNhcmUgcmlzZXMgbGVhZCBjYXNlIHJpc2VzIGluIHN1Y2Nlc3NmdWwgY291bnRpZXMKYGBge3IgZWNobz1GQUxTRX0KcGxvdF9kaXN0cmlidXRpb25fZnJlcShzdWNjZXNzX2V4YW1wbGVzX2Nobmdfc3VtbWVyLCBjaG5nX3N1bW1lcikKYGBgCgojIyMgSW5kaWNhdG9yIENvbWJpbmF0aW9uCmBgYHtyLCByZXN1bHRzPSdoaWRlJywgZWNobz1GQUxTRX0KaW5kaWNhdG9yX2NvbWJfcHJlcGFyZWRfZmFsbCA9IGdldF9hbmRfcGFyc2Vfc2lnbmFscygiMjAyMC0wOS0wMSIsICIyMDIwLTExLTMwIiwgImluZGljYXRvci1jb21iaW5hdGlvbiIsICJubWZfZGF5X2RvY19mYmNfZmJzX2dodCIsIDIwMDAsIDgwKQppbmRpY2F0b3JfY29tYl9wcmVwYXJlZF9zdW1tZXIgPSBnZXRfYW5kX3BhcnNlX3NpZ25hbHMoIjIwMjAtMDYtMDEiLCAiMjAyMC0wOC0zMSIsICJpbmRpY2F0b3ItY29tYmluYXRpb24iLCAibm1mX2RheV9kb2NfZmJjX2Zic19naHQiLCAyMDAwLCA4MCkKYGBgCmBgYHtyIHJlc3VsdHM9ImhpZGUiLCBlY2hvPUZBTFNFfQpjb21iX2ZhbGwgPSBnZXRfaW5jcmVhc2VfcG9pbnRzKGluZGljYXRvcl9jb21iX3ByZXBhcmVkX2ZhbGwkY2FzZXMsIGluZGljYXRvcl9jb21iX3ByZXBhcmVkX2ZhbGwkaW5kaWNhdG9yKQpjb21iX3N1bW1lciA9IGdldF9pbmNyZWFzZV9wb2ludHMoaW5kaWNhdG9yX2NvbWJfcHJlcGFyZWRfc3VtbWVyJGNhc2VzLCBpbmRpY2F0b3JfY29tYl9wcmVwYXJlZF9zdW1tZXIkaW5kaWNhdG9yKQoKc3VjY2Vzc19leGFtcGxlc19jb21iX2ZhbGwgPSBnZXRfc3VjY2Vzc19leGFtcGxlcyhjb21iX2ZhbGwsIHN1Y2Nlc3Nfd2luZG93X21heCA9IDE0LCBzdWNjZXNzX3dpbmRvd19taW4gPSAzKQpzdWNjZXNzX2V4YW1wbGVzX2NvbWJfc3VtbWVyID0gZ2V0X3N1Y2Nlc3NfZXhhbXBsZXMoY29tYl9zdW1tZXIsIHN1Y2Nlc3Nfd2luZG93X21heCA9IDE0LCBzdWNjZXNzX3dpbmRvd19taW4gPSAzKQoKY29tYl9zdWNjZXNzX2ludGVyc2VjdCA9IGludGVyc2VjdChzdWNjZXNzX2V4YW1wbGVzX2NvbWJfZmFsbCwgc3VjY2Vzc19leGFtcGxlc19jb21iX3N1bW1lcikKYGBgCgojIyMjIFdlIGNhbiBwbG90IHNvbWUgb2YgdGhlIGNvdW50aWVzIHdoZXJlIHJpc2VzIGluIHRoZSBpbmRpY2F0b3IgY29tYmluYXRpb24gY29uc2lzdGVudGx5IGxlYWQgcmlzZXMgaW4gY2FzZXMuIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKIyMjIyMgRXhhbXBsZXMgZnJvbSB0aGUgU3VtbWVyCmBgYHtyIGVjaG89RkFMU0V9CnBsb3RfZXhhbXBsZV9saXN0KHN1Y2Nlc3NfZXhhbXBsZXNfY29tYl9zdW1tZXIsIGNvbWJfc3VtbWVyLCAiSW5kaWNhdG9yIENvbWJpbmF0aW9uIENMSSIpCmBgYAoKIyMjIyMgRXhhbXBsZXMgZnJvbSB0aGUgRmFsbApgYGB7ciBlY2hvPUZBTFNFfQpwbG90X2V4YW1wbGVfbGlzdChzdWNjZXNzX2V4YW1wbGVzX2NvbWJfZmFsbCwgY29tYl9mYWxsLCAiSW5kaWNhdG9yIENvbWJpbmF0aW9uIENMSSIpCmBgYAoKIyMjIyMgRXhhbXBsZXMgb2YgY291bnRpZXMgdGhhdCBzaG93IHN1Y2Nlc3NlcyBpbiBib3RoIFN1bW1lciBhbmQgRmFsbApgYGB7ciwgZWNobz1GQUxTRX0KcGxvdF9leGFtcGxlX2ludGVyc2VjdHMoc3VjY2Vzc19leGFtcGxlc19jb21iX3N1bW1lciwgc3VjY2Vzc19leGFtcGxlc19jb21iX2ZhbGwsIGNvbWJfc3VtbWVyLCBjb21iX2ZhbGwsICJJbmRpY2F0b3IgQ29tYmluYXRpb24gQ0xJIikKYGBgCiMjIyMjIEZhbGwgRnJlcXVlbmNpZXMKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmcmVxdWVuY3kgb2YgdGhlIG51bWJlciBvZiBkYXlzIGJ5IHdoaWNoIEluZGljYXRvciBDb21iaW5hdGlvbiByaXNlcyBsZWFkIGNhc2UgcmlzZXMgaW4gc3VjY2Vzc2Z1bCBjb3VudGllcwpgYGB7ciBlY2hvPUZBTFNFfQpwbG90X2Rpc3RyaWJ1dGlvbl9mcmVxKHN1Y2Nlc3NfZXhhbXBsZXNfY29tYl9mYWxsLCBjb21iX2ZhbGwpCmBgYAojIyMjIyBTdW1tZXIgRnJlcXVlbmNpZXMKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmcmVxdWVuY3kgb2YgdGhlIG51bWJlciBvZiBkYXlzIGJ5IHdoaWNoIEluZGljYXRvciBDb21iaW5hdGlvbiByaXNlcyBsZWFkIGNhc2UgcmlzZXMgaW4gc3VjY2Vzc2Z1bCBjb3VudGllcwpgYGB7ciBlY2hvPUZBTFNFfQpwbG90X2Rpc3RyaWJ1dGlvbl9mcmVxKHN1Y2Nlc3NfZXhhbXBsZXNfY29tYl9zdW1tZXIsIGNvbWJfc3VtbWVyKQpgYGAKCiMjCk5vdGUgdGhhdCB0aGUgY291bnRpZXMgc2hvd24gYW5kIGNvdW50ZWQgYXMgInN1Y2Nlc3NmdWwiIGhlcmUgbWV0IHRoZSBmb2xsb3dpbmcgY3JpdGVyaWE6CkFsbCBpbmRpY2F0b3IgcmlzZSBwb2ludHMgd2VyZSBmb2xsb3dlZCBieSBhIGNhc2UgcmlzZSBwb2ludCB3aXRoaW4gMyB0byAxNCBkYXlzIChhbmQgYWxsIGNhc2UgcmlzZSBwb2ludHMgd2VyZSBwcmVjZWRlZCBieSBhbiBpbmRpY2F0b3IgcmlzZSBwb2ludCB3aXRoaW4gdGhlIHNhbWUgdGltZSBwZXJpb2QpLiBUaGlzIG1lYW5zIHRoYXQgdGhlIGRpc3BsYXllZCBjb3VudGllcyBhbG1vc3QgYWx3YXlzIGhhdmUgb25seSBvbmUgcmlzZSBwb2ludCBwZXIgc2lnbmFsIGFuZCBjYXNlICh0aGUgbW9yZSByaXNlIHBvaW50cyB0aGUgaGFyZGVyIGl0IGlzIHRvIG1lZXQgdGhlIGNyaXRlcmlhKS4KCiMjIDxzcGFuPlNlY3Rpb24gNDogUGVyZm9ybWFuY2U8L3NwYW4+ClJlY2FsbCBhbmQgcHJlY2lzaW9uLgoKIyMgPHNwYW4+U2VjdGlvbiA1OiBDb25jbHVzaW9ucyBhbmQgTGltaXRhdGlvbnM8L3NwYW4+CgpgYGB7ciBlY2hvPUZBTFNFfQojIEhFTFBFUiBGVU5DVElPTlMKcGxvdF9leGFtcGxlX2xpc3QgPSBmdW5jdGlvbihzdWNjZXNzX2V4YW1wbGVfbGlzdCwgc2lnbmFsX2RhdGEsIGluZGljYXRvcikgewogIHBsb3RfbGlzdCA9IHZlY3RvcigibGlzdCIsIGxlbmd0aChzdWNjZXNzX2V4YW1wbGVfbGlzdCkgKQogIGZvciAoaSBpbiAxOmxlbmd0aChzdWNjZXNzX2V4YW1wbGVfbGlzdCkpIHsKICAgIHBsb3RfbGlzdFtbaV1dID0gcGxvdF9zaWduYWxzKHNpZ25hbF9kYXRhLCBzdWNjZXNzX2V4YW1wbGVfbGlzdFtbaV1dLCBzbW9vdGhfYW5kX3Nob3dfaW5jcmVhc2VfcG9pbnQ9VFJVRSwgaW5kaWNhdG9yKQogIH0KICBsYXlvdXQgPC0gcmJpbmQoYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpKQogIAogIG1hcnJhbmdlR3JvYihncm9icyA9IHBsb3RfbGlzdCwgbGF5b3V0X21hdHJpeD1sYXlvdXQpCn0KCnBsb3RfZXhhbXBsZV9pbnRlcnNlY3RzID0gZnVuY3Rpb24oc3VjY2Vzc19leGFtcGxlX2xpc3QxLCBzdWNjZXNzX2V4YW1wbGVfbGlzdDIsIHNpZ25hbF9kYXRhMSwgc2lnbmFsX2RhdGEyLCBpbmRpY2F0b3IpIHsKICBkcnNfc3VjY2Vzc19pbnRlcnNlY3QgPSBpbnRlcnNlY3Qoc3VjY2Vzc19leGFtcGxlX2xpc3QxLCBzdWNjZXNzX2V4YW1wbGVfbGlzdDIpCiAgcGxvdF9saXN0ID0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoKGRyc19zdWNjZXNzX2ludGVyc2VjdCkqMikKICBpID0gMQogIGogPSAxCiAgd2hpbGUgKGkgPD0gbGVuZ3RoKGRyc19zdWNjZXNzX2ludGVyc2VjdCkqMiAmJiBqIDw9IGxlbmd0aChkcnNfc3VjY2Vzc19pbnRlcnNlY3QpKSB7CiAgICBwbG90X2xpc3RbW2ldXSA9IHBsb3Rfc2lnbmFscyhzaWduYWxfZGF0YTEsIGRyc19zdWNjZXNzX2ludGVyc2VjdFtbal1dLCBzbW9vdGhfYW5kX3Nob3dfaW5jcmVhc2VfcG9pbnQ9VFJVRSwgaW5kaWNhdG9yKQogICAgcGxvdF9saXN0W1tpKzFdXSA9IHBsb3Rfc2lnbmFscyhzaWduYWxfZGF0YTIsIGRyc19zdWNjZXNzX2ludGVyc2VjdFtbal1dLCBzbW9vdGhfYW5kX3Nob3dfaW5jcmVhc2VfcG9pbnQ9VFJVRSwgaW5kaWNhdG9yKQogICAgaSA9IGkrMgogICAgaiA9IGorMQogIAogIH0KICBsYXlvdXQgPC0gcmJpbmQoYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgYygxLDIpKQogIG1hcnJhbmdlR3JvYihncm9icyA9IHBsb3RfbGlzdCwgbGF5b3V0X21hdHJpeD1sYXlvdXQpCn0KCgoKZ2V0X2xlYWRpbmdfaW5kaWNhdG9yX2RheV9kaXN0cmlidXRpb248LWZ1bmN0aW9uKHN1Y2Nlc3NfZXhhbXBsZXMsIGZpbmFsX2Nhc2VzX2luZGljYXRvcl9saXN0KQp7CiAgY291bnR5X25hbWVzPXVubGlzdChsYXBwbHkoZmluYWxfY2FzZXNfaW5kaWNhdG9yX2xpc3QsIGZ1bmN0aW9uKHgpIHgkZ2VvX3ZhbHVlWzFdKSkKICBzdWNjZXNzX2V4YW1wbGVzX2RhdGEgPSBmaW5hbF9jYXNlc19pbmRpY2F0b3JfbGlzdFt3aGljaChjb3VudHlfbmFtZXMgJWluJSB1bmxpc3Qoc3VjY2Vzc19leGFtcGxlcykpXQogIG5hbWVzKHN1Y2Nlc3NfZXhhbXBsZXNfZGF0YSk8LXVubGlzdChsYXBwbHkoc3VjY2Vzc19leGFtcGxlc19kYXRhLCBmdW5jdGlvbih4KSB4JGdlb192YWx1ZVsxXSkpCiAgIyBwcmludChuYW1lcyhzdWNjZXNzX2V4YW1wbGVzX2RhdGEpKQogIHJldHVybihsYXBwbHkoc3VjY2Vzc19leGFtcGxlc19kYXRhLCBmdW5jdGlvbih4KXsKICAgIGFzLmludGVnZXIoeCR0aW1lX3ZhbHVlW3doaWNoKHgkY2FzZV9yaXNlX3BvaW50PT0xKV0teCR0aW1lX3ZhbHVlW3doaWNoKHgkaW5kaWNhdG9yX3Jpc2VfcG9pbnQ9PTEpXSkKICB9KSkKfQoKcGxvdF9kaXN0cmlidXRpb25fZnJlcSA9IGZ1bmN0aW9uKGV4YW1wbGVzLCBzaWduYWxfZGF0YSkgewogIGFoZWFkcyA9IGdldF9sZWFkaW5nX2luZGljYXRvcl9kYXlfZGlzdHJpYnV0aW9uKGV4YW1wbGVzLCBzaWduYWxfZGF0YSkKICBkaXN0cmlidXRpb24gPSBkYXRhLmZyYW1lKGxlYWRpbmduZXNzPWludGVnZXIoKSwgZnJlcT1pbnRlZ2VyKCkpCiAgZm9yIChpIGluIDE6bGVuZ3RoKGFoZWFkcykpIHsKICAgIGZvciAoaiBpbiAxOmxlbmd0aChhaGVhZHNbW2ldXSkpIHsKICAgICAgaWYgKGFoZWFkc1tbaV1dW1tqXV0gJWluJSBkaXN0cmlidXRpb24kbGVhZGluZ25lc3MpIHsKICAgICAgICBkaXN0cmlidXRpb24kZnJlcVtkaXN0cmlidXRpb24kbGVhZGluZ25lc3MgPT0gYWhlYWRzW1tpXV1bW2pdXV0gPC0gZGlzdHJpYnV0aW9uJGZyZXFbZGlzdHJpYnV0aW9uJGxlYWRpbmduZXNzID09IGFoZWFkc1tbaV1dW1tqXV1dICsgMQogICAgICB9IGVsc2UgewogICAgICAgIGRpc3RyaWJ1dGlvbltucm93KGRpc3RyaWJ1dGlvbikgKyAxLF0gPSBjKGFoZWFkc1tbaV1dW1tqXV0sIDEpCiAgICAgIH0KICAgIH0KICB9CiAgZ2dwbG90KGRpc3RyaWJ1dGlvbiwgYWVzKGxlYWRpbmduZXNzLCBmcmVxKSkgKyAKICAgIGdlb21fYmFyKGFlcyhmaWxsID1sZWFkaW5nbmVzcyksIHN0YXQgPSAnaWRlbnRpdHknKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUpKQp9CgpgYGAK